クロスアカウントで容量の大きいオブジェクトのコピーを行った際に GetObjectTagging operation: Access Denied エラーが発生するので検証してみた
バンクーバーで去り行く夏を惜しんでいる Funa です。
今回はクロスアカウントでs3 cp
コマンドを実行する際にエラーが発生したので、それについてブログ化したいと思います。
エラー内容
クロスアカウントで容量の大きいオブジェクトのコピーを行った際に GetObjectTagging operation: Access Denied
エラーが発生しました。
$ aws s3 cp s3://source-BUCKET/object s3://destination-BUCKET/ copy failed: s3://source-BUCKET/object to s3://destination-BUCKET/object An error occurred (AccessDenied) when calling the GetObjectTagging operation: Access Denied
AWS CLI のバージョンは以下の通りです。
$ aws --version aws-cli/2.9.17 Python/3.11.1 Darwin/22.6.0 source/x86_64 prompt/off
対応方法
これは AWS CLI バージョン 2 のコマンドではマルチパートコピーの際にデフォルトでタグを含めたプロパティをコピーする挙動となっているために発生します。
対応方法としては、以下のいずれかとなります。
① GetObjectTagging
の権限を IAM ポリシーに付与する
AWS CLI を使用して EC2 を介してクロスアカウントでのマルチパートコピーを行う場合は、以下のような IAM ポリシーを IAM ロールに付与して EC2 にアタッチします。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetObject", "s3:GetObjectTagging" //これを追加する ], "Resource": [ "arn:aws:s3:::<送信元バケット名>", "arn:aws:s3:::<送信元バケット名>/*" ] }, { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:PutObjectAcl" ], "Resource": [ "arn:aws:s3:::<送信先バケット名>", "arn:aws:s3:::<送信先バケット名>/*" ] } ] }
② オプション --copy-props
で none
を指定する
aws s3 cp
やaws s3 sync
コマンドを使用する際にオプション --copy-props
にて none
を指定してソースオブジェクトのプロパティを含まないようにします。
・cp | AWS CLI Command Reference, v2
--copy-props (string) Determines which properties are copied from the source S3 object. This parameter only applies for S3 to S3 copies. Valid values are:
none - Do not copy any of the properties from the source S3 object.
①でご対応いただくことが簡単かと思いますが、要件によっては IAM ポリシーを変更できない場合もあるかと思いますので、②で対応を行う場合について検証してみたいと思います。
検証してみた
前提
以下の AWS CLI リファレンスにあるように、AWS CLI でのマルチパートコピーは 8MB 以上の場合に実施されます。
multipart_threshold
Default - 8MB
When uploading, downloading, or copying a file, the S3 commands will switch to multipart operations if the file reaches a given size threshold.
そのため、マルチパートコピーの対象外である 1 MB のファイルと、マルチパートコピーの対象である 20 MB のファイルを用意して検証を行います。
ファイルのアップロード
まずはファイル送信元であるアカウント A の S3 バケット(test-1218-cmca1) にファイルをアップロードしていきます。
1 MB のファイルを S3 バケットにアップロードします。
$ aws s3 cp dogo.png s3://test-1218-cmca1/
dd コマンドで 20 MB のファイルを作成し、S3 バケットにアップロードします。
$ dd if=/dev/zero of=test20M bs=1M count=20 $ aws s3 cp test20M s3://test-1218-cmca1/
IAM の設定
そしてファイル送信元のアカウント A に EC2 インスタンスを立ち上げ、以下の IAM ポリシー (S3-test-policy0929) を含んだ IAM ロール (testrole) を紐付けます。
- 送信元バケット(test-1218-cmca1)
- 送信先バケット(test-178-20230107)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetObject" ], "Resource": [ "arn:aws:s3:::test-1218-cmca1", "arn:aws:s3:::test-1218-cmca1/*" ] }, { "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:PutObject", "s3:PutObjectAcl" ], "Resource": [ "arn:aws:s3:::test-178-20230107", "arn:aws:s3:::test-178-20230107/*" ] } ] }
次に送信先であるアカウント B の送信先バケット(test-178-20230107) に以下のバケットポリシーを設定します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<アカウントAのAWSアカウントID>:role/testrole" }, "Action": [ "s3:GetBucketLocation", "s3:ListBucket" ], "Resource": "arn:aws:s3:::test-178-20230107" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<アカウントAのAWSアカウントID>:role/testrole" }, "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::test-178-20230107/*" } ] }
クロスアカウントでの s3 cp コマンドの実行
アカウント A の EC2インスタンス に SSH 接続をして、クロスアカウントでのコピーを行います。
① 1 MB のファイルのクロスアカウントコピー
$ aws s3 cp s3://test-1218-cmca1/dogo.png s3://test-178-20230107/ copy: s3://test-1218-cmca1/dogo.png to s3://test-178-20230107/dogo.png
1 MB のファイルのクロスアカウントコピーは、オプションの指定なしでも成功しました。
② 20 MB のファイルのクロスアカウントコピー
$ aws s3 cp s3://test-1218-cmca1/test20M s3://test-178-20230107/ copy failed: s3://test-1218-cmca1/test20M to s3://test-178-20230107/test20M An error occurred (AccessDenied) when calling the GetObjectTagging operation: Access Denied
オプションの指定なしでの 20 MB のファイルのクロスアカウントコピーは、GetObjectTagging operation の Access Denied エラーによって失敗しました。
$ aws s3 cp s3://test-1218-cmca1/test20M s3://test-178-20230107/ --copy-props none copy: s3://test-1218-cmca1/test20M to s3://test-178-20230107/test20M
そこで --copy-props
オプションで none
を指定すると、20 MB のファイルでも問題なくクロスアカウントコピーが成功しました。